1 import java.util.*;
2
3 public class Dispatcher extends Thread {
4
5 public final static int statusNEW = 0;
6 public final static int statusWAIT = 1;
7 public final static int statusRUN = 2;
8 public final static int statusPAUSE = 3;
9 public final static int statusSTOP = 4;
10 public final static int statusDIE = 9;
11 public int currentStatus = statusNEW;
12
13 public final static String wordError = "!ERROR!";
14 public final static String wordSucc = "SUCCESS";
15
16 public final static String userName = "bob"; // Temp hack
17 // Defines text for username/pass
18
19 CmdQueue commandsRx;
20 Command currentCommand;
21
22 SlaveUI myUI;
23
24 String target;
25 Logging log;
26
27 String currentScript;
28 Scripter script;
29 ScriptItem sItem;
30 int scriptStep;
31
32 Stack loopStack;
33 int loopItem;
34 Integer loopTemp;
35
36 // Chutes
37 HTTPOut[] out;
38 ReqQueue[] chute;
39 int chuteCount = 4;
40 int useChute;
41
42 // Users
43 int userCount;
44 int userStart;
45
46 int index;
47
48 boolean timeWaitOn = false;
49 long waitTill;
50 public final static int CLOCK_MULTI = 1000;
51
52 boolean syncOn = false;
53
54
55 // helper threads
56 public HTTPIn masterRx;
57
58 public Dispatcher(SlaveUI ui) {
59
60 // initialize me
61 myUI = ui;
62 this.initialize();
63 timeWaitOn = false;
64 loopStack = new Stack();
65 }
66
67 public void run() {
68
69 myUI.putScreenLog("Dispatcher: Im up.");
70
71 masterRx.start();
72
73 // Dispatch loop
74 while (currentStatus != statusDIE) {
75
76 // check command queue
77 if (commandsRx.isCommand()) {
78 currentCommand = commandsRx.getCommand();
79
80 // process command
81 switch(currentCommand.getCommand()) {
82 case Command.cmdNULL:
83 handleNull();
84 break;
85
86 case Command.cmdSTOP:
87 handleStop();
88 break;
89
90 case Command.cmdNEW:
91 handleNew();
92 break;
93
94 case Command.cmdPAUSE:
95 handlePause();
96 break;
97
98 case Command.cmdTARGET:
99 handleTarget();
100 break;
101
102 case Command.cmdGETLOG:
103 handleGetLog();
104 break;
105
106 case Command.cmdGO:
107 handleGo();
108 break;
109
110 case Command.cmdPING:
111 handlePing();
112 break;
113
114 default:
115 myUI.putScreenLog("Software detected fault Dispatch.run");
116 log.post("Software detected fault Dispatch.run");
117 break;
118 }
119 } // end if
120
121 if (currentStatus == statusRUN) {
122
123 if (timeWaitOn == true) {
124
125 // see if timer expired
126 if (log.getTiming() >= waitTill) timeWaitOn = false;
127
128 } else {
129
130 if (syncOn == true) {
131 // See if we can clear a sync
132 handleSync();
133
134 } else {
135 // lets grab a script item, if we have any more
136 if (scriptStep < script.numberItems) {
137 handleScript();
138 } else {
139 //the script is done.
140 //log and change state. (We will want some kind of sync here)
141 log.post("DONE!!! Ending at "+log.getTiming());
142 myUI.putScreenLog("!!! DONE. Script has ended.");
143 currentStatus = statusSTOP;
144 }
145 }
146
147 }
148
149 // take a breather. I may want to remove this. But, it should keep this damned
150 // thread from sucking up soooo much CPU time when relatively idle.
151 try {
152 this.sleep(100);
153 } catch (Exception e) { };
154
155 } else {
156
157 // Idle this thread if nothing is in the command queue and nothing is running
158 if (commandsRx.isCommand() == false) {
159 try {
160 this.sleep(500);
161 } catch (InterruptedException e) {
162 // dont care
163 }
164 }
165 } // end if running
166
167 } // end while
168
169 }
170
171 protected boolean initialize() {
172
173 // Build helpers
174 commandsRx = new CmdQueue();
175
176 log = new Logging();
177
178 masterRx = new HTTPIn(true, commandsRx);
179
180 return true;
181 }
182
183 protected void handleNew() {
184 String r;
185 String i;
186
187 log.post("RX: NEW Command");
188 myUI.putScreenLog("RX: NEW Command");
189
190 // Check against current state
191 switch (currentStatus) {
192
193 case statusSTOP:
194 case statusNEW:
195 script = new Scripter();
196 i = script.load(currentCommand.getStringParam());
197
198 if (script.errors > 0) {
199 myUI.putScreenLog("!!! A NEW command REJECTED due to errors.");
200 myUI.putScreenLog("!!! >>> Processed. "+script.errors+" errors found.");
201 r = formResponse(wordError, "NEW script has been rejected by slave.", i);
202 currentCommand.respond(r);
203 log.post("--> NEW Parse errors: " + script.errors);
204 break;
205 }
206
207 userStart = currentCommand.getIntParam();
208 chuteCount = script.chutes;
209 userCount = script.users;
210 useChute = 0;
211
212 // report
213 log.clear(); // Clear the log here.
214 currentScript = script.name;
215 myUI.setScriptName(currentScript);
216 myUI.putScreenLog("!!! A NEW command accepted.");
217 r = formResponse(wordSucc, "NEW script has been loaded on slave.", i);
218 currentCommand.respond(r);
219
220 log.post("--> NEW Script Name: " + currentScript);
221 currentStatus = statusWAIT;
222
223 break;
224
225 default:
226 myUI.putScreenLog("!!! >>> Rejecting NEW. Script already running or pending.");
227 r = formResponse(wordError, "Rejecting NEW. Already running or pending",
228 "You must STOP the currently running/pending script before posting a NEW script\n");
229 currentCommand.respond(r);
230 log.post("--> NEW Rejected.");
231
232 }
233 }
234
235 protected void handleStop() {
236 String r;
237
238 log.post("RX: STOP Command");
239 myUI.putScreenLog("RX: STOP Command");
240
241 // Check against current state
242 switch (currentStatus) {
243
244 case statusWAIT:
245 case statusRUN:
246 case statusPAUSE:
247
248 myUI.putScreenLog("!!! A STOP command received. Script stopped.");
249 r = formResponse(wordSucc, "Current script stopped.",
250 "The script has been stopped on the slave.");
251 currentCommand.respond(r);
252 log.post("--> Script has been stopped.");
253
254 currentStatus = statusSTOP;
255 log.stopTiming();
256 log.done();
257
258 // Kill the chutes
259 int i = 0;
260 while (i < chuteCount) {
261 try {
262 out[i].stop();
263 } catch (Exception e) {
264 // dont care
265 }
266 i++;
267 }
268 break;
269
270 default:
271 myUI.putScreenLog("!!! >>> Rejecting STOP. Script not running or pending.");
272 r = formResponse(wordError, "Rejecting STOP. Not running or pending",
273 "There is no script currently running or pending.\n");
274 currentCommand.respond(r);
275 log.post("--> STOP Rejected.");
276 }
277 }
278
279 protected void handleNull() {
280 String r;
281 String i;
282
283 myUI.putScreenLog("RX: >> NULL << Command");
284 log.post("RX: >> NULL << Command");
285 log.post("--> Ignored.");
286
287 // report
288 myUI.putScreenLog("!!! Ingoring NULL.");
289 r = formResponse(wordError, "Unrecognized command",
290 "I dont know what to do with that command.");
291 currentCommand.respond(r);
292 }
293
294 protected void handleTarget() {
295 String r;
296
297 log.post("RX: TARGET Command");
298 myUI.putScreenLog("RX: TARGET Command");
299
300 // Check against current state
301 switch (currentStatus) {
302
303 case statusSTOP:
304 case statusNEW:
305
306 target = currentCommand.getStringParam();
307 myUI.setTarget(target);
308
309 // report
310 myUI.putScreenLog("!!! TARGET accepted for :"+target);
311 log.post("--> Target accepted for :"+target);
312 r = formResponse(wordSucc, "TARGET Accepted",
313 "New target is now set for this slave.");
314 currentCommand.respond(r);
315 break;
316
317 default:
318 myUI.putScreenLog("!!! >>> Rejecting TARGET. Script is running or pending.");
319 r = formResponse(wordError, "Rejecting TARGET. Script running or pending",
320 "You cannot set a target while a script is running or pending.\n");
321 currentCommand.respond(r);
322 log.post("--> TARGET Rejected.");
323 }
324 }
325
326 protected void handleGetLog() {
327 String r;
328
329 myUI.putScreenLog("RX: GETLOG Command");
330 log.post("RX: GETLOG Command");
331
332 // report
333 myUI.putScreenLog("!!! Log posted to master.");
334
335 r = formResponse(wordSucc, "Current LOG", log.getLog());
336 currentCommand.respond(r);
337 }
338
339 protected void handlePing() {
340 String r;
341
342 myUI.putScreenLog("RX: PING Command");
343 //log.post("RX: PING Command");
344
345 // report
346 r = formResponse(wordSucc, "PONG", "Status=" + currentStatus + "=");
347 currentCommand.respond(r);
348 }
349
350
351 protected void handleGo() {
352 String r;
353
354 myUI.putScreenLog("RX: GO command");
355
356 // Check against current state
357 switch (currentStatus) {
358
359 case statusWAIT:
360 case statusSTOP:
361 myUI.putScreenLog("!!! A GO command received. Script running.");
362 r = formResponse(wordSucc, "Current script running.",
363 "The script is now running from the start.");
364 currentCommand.respond(r);
365 log.clear();
366 log.startTiming();
367 log.post("RX: GO Command");
368 log.post("--> Script has been started.");
369
370 // Build the chutes
371 int i = 0;
372 chute = new ReqQueue[chuteCount];
373 out = new HTTPOut[chuteCount];
374 while (i < chuteCount) {
375 chute[i] = new ReqQueue();
376 chute[i].init();
377 out[i] = new HTTPOut();
378 out[i].init(chute[i], log);
379 out[i].start();
380 i++;
381 }
382 useChute = 0;
383
384 currentStatus = statusRUN;
385
386 // Start from beginning of script!
387 scriptStep = 0;
388 while(loopStack.empty() != true) { loopTemp = (Integer) loopStack.pop(); }
389 loopItem = ScriptItem.maxLoop; // remove any pending loops
390
391 break;
392
393 case statusPAUSE:
394
395 myUI.putScreenLog("!!! A GO command received. Script restarted from PAUSE.");
396 r = formResponse(wordSucc, "Current script restarted.",
397 "The script is now running from a pause.");
398 currentCommand.respond(r);
399 log.resumeTiming();
400 log.post("RX: GO Command");
401 log.post("--> Script has been restarted from a pause.");
402
403 currentStatus = statusRUN;
404 break;
405
406 default:
407 //log.post("RX: GO Command");
408 myUI.putScreenLog("!!! >>> Rejecting GO. Script not ready or already running.");
409 r = formResponse(wordError, "Rejecting GO. Already running or not ready.",
410 "A script is already running or one has not been loaded.\n");
411 currentCommand.respond(r);
412 log.post("--> GO Rejected.");
413 }
414 }
415
416 protected void handlePause() {
417 String r;
418
419 myUI.putScreenLog("RX: PAUSE Command");
420 log.post("RX: PAUSE Command");
421
422 // Check command against state
423 if (currentStatus != statusRUN) {
424 myUI.putScreenLog("!!! >>> Rejecting PAUSE. Not currently running.");
425 r = formResponse(wordError, "Rejecting PAUSE.",
426 "No script is currently running.\n");
427 currentCommand.respond(r);
428 log.post("--> PAUSE Rejected. Not running.");
429 return;
430 }
431
432 currentStatus = statusWAIT;
433 log.pauseTiming();
434
435 // report
436 myUI.putScreenLog("!!! PAUSE accepted. ");
437 log.post("--> PAUSE Accepted:");
438 r = formResponse(wordSucc, "PAUSE Accepted", "Script is now paused.");
439 currentCommand.respond(r);
440 }
441
442 private String formResponse(String title, String note, String content) {
443 StringBuffer r = new StringBuffer();
444 r.append("<HTML><HEAD><TITLE>"+title+"</TITLE></HEAD><BODY><H2>"+note);
445 r.append("</H2><PRE>"+content+"</PRE></BODY></HTML>");
446 return r.toString();
447 }
448
449 private void handleScript() {
450
451 sItem = script.getItem(scriptStep);
452 scriptStep++;
453 //System.out.println("TOKEN: " + sItem.token);
454 switch(sItem.token) {
455
456 case ScriptItem.tokenPut:
457 int i;
458 if (sItem.id == 0) {
459 i = useChute;
460 useChute++;
461 if (useChute >= chuteCount) useChute = 0;
462 } else {
463 i = (script.userList[sItem.id]);
464 }
465 put( sItem.text, sItem.id, i );
466 break;
467
468 case ScriptItem.tokenIndexPut:
469 if (index > userCount) {
470 myUI.putScreenLog("Software detected fault Dispatch.handleScript-INDEX out of bounds");
471 log.post("Software detected fault Dispatch.handleScript-INDEX Inc of bounds. Used index = 1");
472 index = 1;
473 }
474 try {
475 put( sItem.text, index, script.userList[index] );
476 } catch (Exception e) {
477 System.out.println("INDEX OOB = " + index);
478 myUI.putScreenLog("Software detected fault Dispatch.handleScript-INDEX out of bounds");
479 log.post("Software detected fault Dispatch.handleScript-INDEX out of bounds");
480 }
481 break;
482
483 case ScriptItem.tokenIndexWait:
484 if (index > userCount) {
485 myUI.putScreenLog("Software detected fault Dispatch.handleScript-INDEX WAIT out of bounds");
486 log.post("Software detected fault Dispatch.handleScript-INDEX WAIT of bounds. Used index = 1");
487 index = 1;
488 }
489 try {
490 chuteWait(index, (sItem.count * CLOCK_MULTI));
491 } catch (Exception e) {
492 System.out.println("INDEX WAIT OOB = " + index);
493 myUI.putScreenLog("Software detected fault Dispatch.handleScript-INDEX WAIT out of bounds");
494 log.post("Software detected fault Dispatch.handleScript-INDEX WAIT out of bounds");
495 }
496 break;
497
498 case ScriptItem.tokenWait:
499 if (sItem.id == 0) {
500 // General Wait
501 timeWaitOn = true;
502 log.post("WAIT : Time now : "+log.getTiming());
503 waitTill = log.getTiming() + (sItem.count * CLOCK_MULTI);
504 log.post(" : until "+waitTill);
505 } else {
506 // Chute wait. Follows a user
507 chuteWait(sItem.id, (sItem.count * CLOCK_MULTI));
508 }
509 break;
510
511 case ScriptItem.tokenLoop:
512
513 // If we have any loops pending, push the loopItem onto a stack so
514 // we can remember the loop count later.
515 if (loopItem != ScriptItem.maxLoop) {
516 loopTemp = new Integer(loopItem);
517 loopStack.push(loopTemp);
518 }
519 loopItem = sItem.count;
520 break;
521
522 case ScriptItem.tokenEndLoop:
523
524 loopItem--;
525 if (loopItem > 0) {
526 scriptStep = sItem.count + 1;
527
528 } else {
529 // Do we need to recover a outside loop?
530 if (loopStack.empty() == false) {
531 loopTemp = (Integer) loopStack.pop();
532 loopItem = loopTemp.intValue();
533
534 } else {
535 loopItem = ScriptItem.maxLoop; // clear the pending loop (or, adding a new
536 // loop will be nested.)
537 }
538 }
539 break;
540
541 case ScriptItem.tokenEnd:
542 log.post("END : Ending at "+log.getTiming());
543 break;
544
545 case ScriptItem.tokenSync:
546 log.post("SYNC: Starting at "+log.getTiming());
547 syncOn = true;
548 break;
549
550 case ScriptItem.tokenIndexSet:
551 index = sItem.count;
552 System.out.println("INDEX = " + index);
553 break;
554
555 case ScriptItem.tokenIndexInc:
556 index++;
557 break;
558
559 case ScriptItem.tokenName:
560 default:
561 myUI.putScreenLog("Software detected fault Dispatch.handleScript-tokenDEFAULT");
562 log.post("Software detected fault Dispatch.handleScript-tokenDEFAULT");
563 break;
564
565 }
566
567 }
568
569 private void handleSync() {
570
571 int i = 0;
572 int size = 0;
573 int idleClear = 0;
574
575 while (i < chuteCount) {
576 size = size + chute[i].size();
577 if (out[i].idle == false) idleClear++;
578 i++;
579 }
580 if ((size == 0)&&(idleClear == 0)) {
581 log.post("SYNC: Sync cleared.");
582 syncOn = false;
583 }
584
585 }
586
587 private void put(String text, int user, int chuteNum) {
588 StringBuffer s = new StringBuffer();
589 Request r = new Request();
590 int c = chuteNum - 1; // The chute is one less as an array index;
591 int rover = 0;
592 int size = text.length();
593 char temp;
594
595 // Lets chug through this dog and build the URL. Replace any idChar with
596 // a username/password string.
597 s.append("http://"+target);
598 while (rover < size) {
599 temp = text.charAt(rover);
600 if (temp == ScriptItem.idChar) {
601 s.append(userName + ((user-1)+userStart));
602 } else {
603 s.append(temp);
604 }
605 rover++;
606 }
607
608 r.type = Request.reqPUT;
609 r.text = s.toString();
610
611 //System.out.println("QUEUE " + c + ": PUT : " + r.text);
612 //System.out.println("QUEUE " + c + ": PUT : " + text);
613 chute[c].put(r);
614 }
615
616 private void chuteWait(int user, int time) {
617 Request r = new Request();
618 int c;
619
620 c = script.userList[user]-1; // The chute is one less as an array index;
621 r.type = Request.reqWAIT;
622 r.intParam = time;
623
624 System.out.println("QUEUE " + c + ": WAIT " + time);
625 chute[c].put(r);
626 }
627
628
629 }
630
|